#ifndef MFC_H
#define MFC_H

// wrappers for required MFC classes
// makes life a bit less annoying

#include <wx/list.h>
#include <wx/hashmap.h>
#include <wx/dynarray.h>
#include <wx/listimpl.cpp>

WX_DEFINE_ARRAY(void*,VoidArray);
WX_DECLARE_LIST(void,VoidList);
// da map
WX_DECLARE_HASH_MAP(unsigned int,void*,wxIntegerHash,wxIntegerEqual,VoidHash);
//typedef VoidList::Node* POSITION;

typedef struct {
  VoidHash::iterator it;
  VoidList::Node* node;
} _POSITION;

typedef _POSITION* POSITION;

//typedef void* POSITION;

#include <glib.h>
// basic list
// ok, own implementation. you can't do the reasonaby otherwise
template<class TYPE,class ARG_TYPE>
class CList : public wxObject
{
  typedef struct MyNode {
    struct MyNode* next,* prev;
    TYPE data;
  } MYNODE;

 protected:
  //VoidList internalList;
  MYNODE* internalList;
  MYNODE* tail;
  int count;

  void freeNode(MYNODE* n) {
    delete n;
  }
  MYNODE* newNode(ARG_TYPE data) {
    MYNODE* n=new MYNODE;
    n->prev=n->next=NULL;
    n->data=data;
    return n;
  }

 public:
  CList(int none=0) {internalList=NULL; tail=NULL; count=0;}; 
  // hmm.. you really want to DELETE the list too!
  ~CList() {RemoveAll();};

  int GetCount() const {
    return count;//g_list_length(internalList);
  };
  int GetSize() const {
    return count;//g_list_length(internalList);
  }; 
  bool IsEmpty() const {
    return count==0; //g_list_length(internalList)==0;
  };
  TYPE& GetHead() {
    if(internalList) {
      return internalList->data;
    } else {
      printf("DO NOT CALL WITH EMPTY LIST\n");
      exit(1);
    }
  };
  TYPE GetHead() const {
    if(internalList) {
      return internalList->data;
    } else {
      return (TYPE)0;
    }
  };
  TYPE& GetTail() {
    if(tail) {
      return tail->data;
    } else {
      printf("DONT CALL WITH EMPTY LIST\n");
      exit(1);
    }
  };
  TYPE GetTail() const {
    if(tail) {
      return tail->data;
    } else {
      return (TYPE)0;
    }
  };
  TYPE RemoveHead() {
    if(internalList) {
      MYNODE* old=internalList;
      TYPE oldvalue=old->data;
      
      // advance head
      internalList=internalList->next; 
      // if not null, then there are still items in the list
      if(internalList)
	internalList->prev=NULL; // and this is the head
      else
	tail=NULL; // otherwise.. no more list and tail

      freeNode(old);
      count--;
      return oldvalue;
    }
    // otherwise we are iterating on a empty list.. 
    return (TYPE)0;
  };
  TYPE RemoveTail() {
    if(tail) {
      MYNODE* old=tail;
      TYPE olddata=tail->data;

      // move tail to previous node
      tail=tail->prev;
      // is there list anymore?
      if(tail) 
	tail->next=NULL; // yes. this is the tail
      else
	internalList=NULL; // no. list has vanished
      freeNode(tail);
      count--;
      return olddata;
    }
    // iterating on an empty list
    return (TYPE)0;
  };
  POSITION AddHead(ARG_TYPE uusi) {
    MYNODE* newnode=newNode(uusi);
    // we are adding to head!
    newnode->next=internalList;
    if(internalList)
      internalList->prev=newnode;
    else
      tail=newnode;
    internalList=newnode;
    count++;
    // return position to head
    return (POSITION)internalList;
  };
  POSITION AddTail(ARG_TYPE uusi) {
    MYNODE* newnode=newNode(uusi);
    // and to the tail
    newnode->prev=tail;
    if(tail)
      tail->next=newnode;
    else
      internalList=newnode;
    tail=newnode;
    count++;
    return (POSITION)tail;
  };
  POSITION Append(ARG_TYPE uusi) { 
    // addtail
    return AddTail(uusi);
  };
  void RemoveAll() {
    MYNODE* first=internalList;
    while(first) {
      MYNODE* n=first->next;
      freeNode(first);
      first=n;
    }
    internalList=tail=NULL;
    count=0;
  };
  POSITION GetHeadPosition() const {
    return (POSITION)internalList;
  };
  POSITION GetTailPosition() const {
    return (POSITION)tail;
  };
  TYPE& GetNext(POSITION& pos) {
    MYNODE*n = (MYNODE*)pos;
    if(n) {
      TYPE& data=n->data;
      n=n->next;
      pos=(POSITION)n;
      return data;
    } else {
      printf("DO NOT CALL WITH EMPTY LIST!\n");
      exit(1);
    }
  };
  TYPE GetNext(POSITION& pos) const {
    MYNODE*n = (MYNODE*)pos;
    if(n) {
      TYPE data=n->data;
      n=n->next;
      pos=(POSITION)n;
      return data;
    } else {
      return (TYPE)0;
    }
  };
  TYPE& GetPrev(POSITION& pos) {
    MYNODE*n=(MYNODE*)pos;
    if(n) {
      TYPE& data=n->data;
      n=n->prev;
      pos=(POSITION)n;
      return data;
    } else {
      printf("DO NOT CALL WITH EMPTY LIST\n");
      exit(1);
    }
  };
  TYPE GetPrev(POSITION& pos) const {
    MYNODE*n=(MYNODE*)pos;
    if(n) {
      TYPE data=n->data;
      n=n->prev;
      pos=(POSITION)n;
      return data;
    } else {
      return (TYPE)0;
    }
  };
  TYPE& GetAt(POSITION pos) {
    MYNODE*n=(MYNODE*)pos;
    if(n) {
      return n->data;
    }
    printf("DO NOT CALL WITH EMPTY LIST\n");
    exit(1);
  };
  TYPE GetAt(POSITION pos) const {
    MYNODE*n=(MYNODE*)pos;
    if(n) {
      return n->data;
    }
    return (TYPE)0;
  };
  void RemoveAt(POSITION pos) {
    MYNODE*n =(MYNODE*)pos;
    if(n) {
      // are we removing the head?
      if(internalList==n) {
	// yes
	internalList=n->next;
      } else {
	// no
	n->prev->next=n->next;
      }
      // is it tail too?
      if(tail==n) {
	// yes
	tail=n->prev;
      } else {
	// no
	n->next->prev=n->prev;
      }
      freeNode(n);
      count--;
    } 
  };
  void InsertAfter(POSITION pos,ARG_TYPE data) {
    MYNODE* n=(MYNODE*)pos;
    if(n) {
      MYNODE* newnode=newNode(data);
      newnode->prev=n;
      newnode->next=n->next;
      if(n->next) {
	n->next->prev=newnode;
      } else {
	// it's tail
	tail=newnode;
      }
      n->next=newnode;
      // increase count here. not after addtail()
      count++;
    } else {
      // just append
      pos=AddTail(data);
    }
  };
  POSITION Find(ARG_TYPE searchValue,POSITION startAfter=NULL) const {
    MYNODE *n=internalList;
    if(startAfter) n=((MYNODE*)startAfter)->next;
    while(n) {
      if(n->data==searchValue) {
	return (POSITION)n;
      }
      n=n->next;
    }
    return (POSITION)0;
  };
  POSITION FindIndex(int nIndex) const {
    MYNODE*n=internalList;
    for(int i=0;i<nIndex;i++) {
      if(n) {
	n=n->next;
      } else {
	// past the end
	return (POSITION)0;
      }
    }
    return (POSITION)n;
  };
};

class CPtrList;

// typedptrlist is just an instance of ordinary list...
template<class BASE_CLASS, class TYPE>
class CTypedPtrList : public CList<TYPE,TYPE>
{
 public:
  CTypedPtrList(int nBlockSize=0) {};
};


#include <stdarg.h>
// same for string list
class CString : public wxString {
 public:
  CString() : wxString() {};
  CString(wxChar*ptr)
    : wxString(ptr) {};
  CString(const wxChar*ptr)
    : wxString(ptr) {};
  const char* GetBuffer() { return (const char*)GetData();};
  int GetLength() const {
    return Length();
  };
  void Format(const wxChar* pszFormat,...) {
    va_list argptr;
    va_start(argptr,pszFormat);
    PrintfV(pszFormat,argptr);
    va_end(argptr);
  };
  int Find(CString what) const {
    return wxString::Find(what);
  };
  CString Mid(int from,int len) {
    return CString(wxString::Mid(from,len).GetData());
  };
};

WX_DECLARE_LIST(CString,stringList);

class CStringList : public stringList
{  
 public:
  CStringList(int nblocks=0) {};

  POSITION GetHeadPosition() {
    return (POSITION)GetFirst();
  };
  CString GetNext(POSITION& pos) {
    stringList::Node* nod=(stringList::Node*)pos;
    CString retval=*(nod->GetData());
    nod=nod->GetNext();
    pos=(POSITION)nod;
    return retval;
  };
  CString GetAt(POSITION pos) {
    stringList::Node* nod=(stringList::Node*)pos;
    return *(nod->GetData());
  }
};

// default hasher
template<class ARG_KEY>
unsigned int HashKey(ARG_KEY key)
{
  return ((unsigned int)(void*)(unsigned long)key);
}

template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE>
class CMap : public wxObject 
{
 protected:
  VoidHash internalHash;

 public:
  CMap(int blocks=0) {};
  ~CMap() {internalHash.clear();}

  int GetCount() const {
    return internalHash.size();
  }
  bool IsEmpty() const {
    return internalHash.empty();
  }
  bool Lookup(ARG_KEY key,VALUE& value) {
    VoidHash::iterator it=internalHash.find(HashKey(key));
    if(it!=internalHash.end()) {
      value=(VALUE)it->second;
      return true;
    } else return false;
  };
  void SetAt(ARG_KEY key,ARG_VALUE newValue) {
    internalHash[HashKey(key)]=(void*)newValue;
  };
  VALUE& operator[](ARG_KEY key) {
    return (VALUE&)internalHash[HashKey(key)];
  };
  bool RemoveKey(ARG_KEY key) {
    int x=internalHash.erase(HashKey(key));
    if(x) return true; else return false;
  };
  void RemoveAll() {
    internalHash.clear();
  };
  POSITION GetStartPosition() /*const*/ {
    if(internalHash.empty()) {
      return 0;
    } else {
      positioner.it=internalHash.begin();
      return (POSITION)&positioner;
    }
  };
  void GetNextAssoc(POSITION& nextPos,KEY& key,VALUE& val) {
    VoidHash::iterator it=nextPos->it;
    key=(KEY&)it->first;
    val=(VALUE)it->second;
    it++;
    if(it!=internalHash.end()) {
      positioner.it=it;
      nextPos=(POSITION)&positioner;
    } else {
      nextPos=0;
    }
  };
  unsigned int GetHashTableSize() const {
    return 1024;
  };
  void InitHashTable(unsigned int size,bool allocnow=true) {
    // nothing here
  };

private:
  VoidHash::const_iterator myit;
  _POSITION positioner;
};

template<class TYPE,class ARG_TYPE>
class CArray : public wxObject {
 private:
  VoidArray intArr;
 public:
  CArray() {};
  ~CArray() {intArr.Empty();}
  int GetSize() const {
    return intArr.GetCount();   
  };
  int GetCount() const {
    return intArr.GetCount();
  };
  int GetUpperBound() const {
    return intArr.GetCount()+1;
  };
  void SetSize(int newsiz,int growby=-1) {
    intArr.Alloc(newsiz);
  };
  bool IsEmpty() const {
    return intArr.IsEmpty();
  };
  void RemoveAll() {
    intArr.Empty();
  };

  void RemoveAt(int nIndex) {
    intArr.RemoveAt(nIndex);
  };

  TYPE GetAt(int nIndex) const {
    return (TYPE)intArr.Item(nIndex);
  };
  void SetAt(int nIndex,ARG_TYPE newElem) {
    intArr[nIndex]=(void*)newElem;
  };
  TYPE& ElementAt(int nIndex) {
    return (TYPE&)intArr.Item(nIndex);
  };
  int Add(ARG_TYPE newElem) {
    intArr.Add((void*)newElem);
    return 0;
  };
  void InsertAt(int nIndex,ARG_TYPE newElem) {
    intArr.Insert((void*)newElem,nIndex,1);
  }

  TYPE operator[](int nIndex) const {
    return (TYPE)intArr[nIndex];
  };
  TYPE& operator[](int nIndex) {
    return (TYPE&)intArr[nIndex];
  };
};

#endif
